package com.mocha.util;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class DateUtil {


    public static final long SECOND = 1000L;
    public static final long MINUTE = 60000L;
    public static final long HOUR = 3600000L;
    public static final long DAY = 86400000L;
    public static final String TIME_BEGIN = " 00:00:00";
    public static final String TIME_END = " 23:59:59";
    public static final String MONTH_PATTERN = "yyyy-MM";
    public static final String DEFAULT_PATTERN = "yyyyMMdd";
    public static final String DOT_PATTERN = "yyyy.MM.dd";
    public static final String FULL_PATTERN = "yyyyMMddHHmmss";
    public static final String FULL_STANDARD_PATTERN = "yyyyMMdd HH:mm:ss";
    public static final String CHINESE_PATTERN = "yyyy-MM-dd";
    public static final String FULL_CHINESE_PATTERN = "yyyy-MM-dd HH:mm:ss";

    public DateUtil() {
    }

    public static Calendar getCurrentCalendar() {
        return Calendar.getInstance();
    }

    public static Timestamp getCurrentTimestamp() {
        return new Timestamp(System.currentTimeMillis());
    }

    public static Date getCurrentDatetime() {
        return new Date(System.currentTimeMillis());
    }

    public static Date getCurrentDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.set(10, 0);
        calendar.set(12, 0);
        calendar.set(13, 0);
        calendar.set(14, 0);
        return new Date(calendar.getTimeInMillis());
    }

    public static String getYear() {
        return formatDate("yyyy");
    }

    public static String getMonth() {
        return formatDate("MM");
    }

    public static String getDay() {
        return formatDate("dd");
    }

    public static final int getYear(Date date) {
        if (date == null) {
            return -1;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(1);
        }
    }

    public static final int getYear(long millis) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(millis);
        return calendar.get(1);
    }

    public static final int getMonth(Date date) {
        if (date == null) {
            return -1;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(2) + 1;
        }
    }

    public static final int getMonth(long millis) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(millis);
        return calendar.get(2) + 1;
    }

    public static final int getDay(Date date) {
        if (date == null) {
            return -1;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(5);
        }
    }

    public static final int getDay(long millis) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(millis);
        return calendar.get(5);
    }

    public static final int getHour(Date date) {
        if (date == null) {
            return -1;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(11);
        }
    }

    public static final int getMinute(Date date) {
        if (date == null) {
            return -1;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(12);
        }
    }

    public static final int getSecond(Date date) {
        if (date == null) {
            return -1;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(13);
        }
    }

    public static final int getHour(long millis) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(millis);
        return calendar.get(11);
    }

    public static String getChinesePatternNow() {
        return formatDate("yyyy-MM-dd");
    }

    public static String getFullChinesePatternNow() {
        return formatDate("yyyy-MM-dd HH:mm:ss");
    }

    public static String getChinesePatternNow(Date date) {
        return formatDate(date, "yyyy-MM-dd");
    }

    public static String getFullCNPatternNow(Date date) {
        return formatDate(date, "yyyy-MM-dd HH:mm:ss");
    }

    public static String formatDate(Date date) {
        return formatDate(date, "yyyyMMdd");
    }

    public static String formatDate(Date date, String format) {
        return null != date && !EmptyUtil.isEmpty(format) ? (new SimpleDateFormat(format)).format(date) : null;
    }

    public static String formatDate(String format) {
        return formatDate(new Date(), format);
    }

    public static Date parseDate(String sDate) {
        return parseDate(sDate, "yyyyMMdd", (Date)null);
    }

    public static Date parseDate(String sDate, String format) {
        return parseDate(sDate, format, (Date)null);
    }

    public static Date parseDate(String sDate, String format, Date defaultValue) {
        if (!EmptyUtil.isEmpty(sDate) && !EmptyUtil.isEmpty(format)) {
            SimpleDateFormat formatter = new SimpleDateFormat(format);

            try {
                return formatter.parse(sDate);
            } catch (ParseException e) {
                return defaultValue;
            }
        } else {
            return defaultValue;
        }
    }

    public static Date addMonths(Date date, int months) {
        if (months == 0) {
            return date;
        } else if (date == null) {
            return null;
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(2, months);
            return cal.getTime();
        }
    }

    public static Date addDays(Date date, int days) {
        if (days == 0) {
            return date;
        } else if (date == null) {
            return null;
        } else {
            Calendar cal = GregorianCalendar.getInstance();
            cal.setTime(date);
            cal.add(5, days);
            return cal.getTime();
        }
    }

    public static Date addMins(Date date, int mins) {
        if (mins == 0) {
            return date;
        } else if (date == null) {
            return null;
        } else {
            Calendar cal = GregorianCalendar.getInstance();
            cal.setTime(date);
            cal.add(12, mins);
            return cal.getTime();
        }
    }

    public static int compareDate(Date first, Date second) {
        if (first == null && second == null) {
            return 0;
        } else if (first == null) {
            return -1;
        } else if (second == null) {
            return 1;
        } else if (first.before(second)) {
            return -1;
        } else {
            return first.after(second) ? 1 : 0;
        }
    }

    public static Date getSmaller(Date first, Date second) {
        if (first == null && second == null) {
            return null;
        } else if (first == null) {
            return second;
        } else if (second == null) {
            return first;
        } else if (first.before(second)) {
            return first;
        } else {
            return first.after(second) ? second : first;
        }
    }

    public static Date getLarger(Date first, Date second) {
        if (first == null && second == null) {
            return null;
        } else if (first == null) {
            return second;
        } else if (second == null) {
            return first;
        } else if (first.before(second)) {
            return second;
        } else {
            return first.after(second) ? first : first;
        }
    }

    public static boolean isDateBetween(Date date, Date begin, Date end) {
        int c1 = compareDate(begin, date);
        int c2 = compareDate(date, end);
        return c1 == -1 && c2 == -1 || c1 == 0 || c2 == 0;
    }

    public static boolean isSameMonth(Date date1, Date date2) {
        if (date1 == null && date2 == null) {
            return true;
        } else if (date1 != null && date2 != null) {
            Calendar cal1 = GregorianCalendar.getInstance();
            cal1.setTime(date1);
            Calendar cal2 = GregorianCalendar.getInstance();
            cal2.setTime(date2);
            return isSameMonth(cal1, cal2);
        } else {
            return false;
        }
    }

    public static boolean isSameDay(Date date1, Date date2) {
        if (date1 == null && date2 == null) {
            return true;
        } else if (date1 != null && date2 != null) {
            Calendar cal1 = GregorianCalendar.getInstance();
            cal1.setTime(date1);
            Calendar cal2 = GregorianCalendar.getInstance();
            cal2.setTime(date2);
            return cal1.get(1) == cal2.get(1) && cal1.get(2) == cal2.get(2) && cal1.get(5) == cal2.get(5);
        } else {
            return false;
        }
    }

    public static boolean isSameMonth(Calendar cal1, Calendar cal2) {
        if (cal1 == null && cal2 == null) {
            return true;
        } else if (cal1 != null && cal2 != null) {
            return cal1.get(1) == cal2.get(1) && cal1.get(2) == cal2.get(2);
        } else {
            return false;
        }
    }

    public static Date getStartOfDate(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = GregorianCalendar.getInstance();
            cal.setTime(date);
            cal.set(11, 0);
            cal.set(12, 0);
            cal.set(13, 0);
            cal.set(14, 0);
            return cal.getTime();
        }
    }

    public static Date getEndOfDate(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = GregorianCalendar.getInstance();
            cal.setTime(date);
            cal.set(11, 23);
            cal.set(12, 59);
            cal.set(13, 59);
            cal.set(14, 999);
            return cal.getTime();
        }
    }

    public static Date getPreviousMonday() {
        Calendar cd = Calendar.getInstance();
        int dayOfWeek = cd.get(7) - 1;
        Date date;
        if (dayOfWeek == 1) {
            date = addDays(cd.getTime(), -7);
        } else {
            date = addDays(cd.getTime(), -6 - dayOfWeek);
        }

        return getStartOfDate(date);
    }

    public static Date getMondayBefore4Week() {
        Calendar cd = Calendar.getInstance();
        int dayOfWeek = cd.get(7) - 1;
        Date date;
        if (dayOfWeek == 1) {
            date = addDays(cd.getTime(), -28);
        } else {
            date = addDays(cd.getTime(), -27 - dayOfWeek);
        }

        return getStartOfDate(date);
    }

    public static Date getCurrentMonday() {
        Calendar cd = Calendar.getInstance();
        int dayOfWeek = cd.get(7) - 1;
        Date date;
        if (dayOfWeek == 1) {
            date = cd.getTime();
        } else {
            date = addDays(cd.getTime(), 1 - dayOfWeek);
        }

        return getStartOfDate(date);
    }

    public static Date getEndOfMonth(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.set(2, calendar.get(2) + 1);
            calendar.set(5, 0);
            calendar.set(11, 12);
            calendar.set(12, 0);
            calendar.set(13, 0);
            calendar.set(14, 0);
            return new Date(calendar.getTimeInMillis());
        }
    }

    public static Date getFirstOfMonth(Date date) {
        Date lastMonth = addMonths(date, -1);
        lastMonth = getEndOfMonth(lastMonth);
        return addDays(lastMonth, 1);
    }

    public static Date getWeekBegin(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = new GregorianCalendar();
            cal.setTime(date);

            for(int dw = cal.get(7); dw != 2; dw = cal.get(7)) {
                cal.add(5, -1);
            }

            return cal.getTime();
        }
    }

    public static Date getWeekEnd(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = new GregorianCalendar();
            cal.setTime(date);

            for(int dw = cal.get(7); dw != 1; dw = cal.get(7)) {
                cal.add(5, 1);
            }

            return cal.getTime();
        }
    }

    public static boolean inFormat(String sourceDate, String format) {
        if (sourceDate != null && !EmptyUtil.isEmpty(format)) {
            try {
                SimpleDateFormat dateFormat = new SimpleDateFormat(format);
                dateFormat.setLenient(false);
                dateFormat.parse(sourceDate);
                return true;
            } catch (Exception e) {
                return false;
            }
        } else {
            return false;
        }
    }

    public static int getNumberOfSecondsBetween(double d1, double d2) {
        return d1 != 0.0D && d2 != 0.0D ? (int)(Math.abs(d1 - d2) / 1000.0D) : -1;
    }

    public static int getNumberOfMonthsBetween(Date begin, Date end) {
        if (begin != null && end != null) {
            Calendar cal1 = Calendar.getInstance();
            cal1.setTime(begin);
            Calendar cal2 = Calendar.getInstance();
            cal2.setTime(end);
            return (cal2.get(1) - cal1.get(1)) * 12 + (cal2.get(2) - cal1.get(2));
        } else {
            return -1;
        }
    }

    public static long getNumberOfMinuteBetween(Date begin, Date end) {
        if (begin != null && end != null) {
            long millisec = end.getTime() - begin.getTime();
            return millisec / 60000L;
        } else {
            return -1L;
        }
    }

    public static long getNumberOfHoursBetween(Date begin, Date end) {
        if (begin != null && end != null) {
            long millisec = end.getTime() - begin.getTime() + 1L;
            return millisec / 3600000L;
        } else {
            return -1L;
        }
    }

    public static long getNumberOfDays(Date begin, Date end) {
        if (begin != null && end != null) {
            Date d1 = getStartOfDate(begin);
            Date d2 = getStartOfDate(end);
            return getNumberOfDaysBetween(d1, d2);
        } else {
            return -1L;
        }
    }

    public static long getNumberOfDays(String begin, Date end) {
        Date d1 = getStartOfDate(parseDate(begin, "yyyy-MM-dd HH:mm:ss"));
        return getNumberOfDays(d1, end);
    }

    public static long getNumberOfDays(String begin, String end) {
        Date d1 = getStartOfDate(parseDate(begin, "yyyy-MM-dd HH:mm:ss"));
        Date d2 = getStartOfDate(parseDate(end, "yyyy-MM-dd HH:mm:ss"));
        return getNumberOfDays(d1, d2);
    }

    public static long getNumberOfDaysBetween(Date begin, Date end) {
        if (begin != null && end != null) {
            long millisec = end.getTime() - begin.getTime();
            return millisec / 86400000L;
        } else {
            return -1L;
        }
    }

    public static long getNumberOfDaysBetween(Calendar before, Calendar after) {
        if (before != null && after != null) {
            before.clear(14);
            before.clear(13);
            before.clear(12);
            before.clear(11);
            after.clear(14);
            after.clear(13);
            after.clear(12);
            after.clear(11);
            long elapsed = after.getTime().getTime() - before.getTime().getTime();
            return elapsed / 86400000L;
        } else {
            return -1L;
        }
    }

    public static Date getRemoteDate(String url) {
        if (url == null) {
            return null;
        } else {
            try {
                URLConnection uc = (new URL(url)).openConnection();
                uc.connect();
                return new Date(uc.getDate());
            } catch (IOException e) {
                return new Date();
            }
        }
    }

    public static Date getWeekBegin(Calendar tmp) {
        if (tmp == null) {
            return null;
        } else {
            Calendar ctmp = new GregorianCalendar(tmp.get(1), tmp.get(2), tmp.get(5));

            for(int dw = ctmp.get(7); dw != 2; dw = ctmp.get(7)) {
                ctmp.add(5, -1);
            }

            return ctmp.getTime();
        }
    }

    public static Date getWeekEnd(Calendar tmp) {
        if (tmp == null) {
            return null;
        } else {
            Calendar ctmp = new GregorianCalendar(tmp.get(1), tmp.get(2), tmp.get(5), 23, 0);

            for(int dw = ctmp.get(7); dw != 1; dw = ctmp.get(7)) {
                ctmp.add(5, 1);
            }

            return ctmp.getTime();
        }
    }

    public static Date getQuarterBegin(Calendar tmp) {
        if (tmp == null) {
            return null;
        } else {
            Calendar ctmp = new GregorianCalendar(tmp.get(1), tmp.get(2), tmp.get(5));
            int month = ctmp.get(2);
            int offset = -(month % 3);
            ctmp.add(2, offset);
            return getFirstOfMonth(ctmp.getTime());
        }
    }

    public static Date getQuarterEnd(Calendar tmp) {
        if (tmp == null) {
            return null;
        } else {
            Calendar ctmp = new GregorianCalendar(tmp.get(1), tmp.get(2), tmp.get(5), 23, 0);
            int month = ctmp.get(2);
            int offset = 2 - month % 3;
            ctmp.add(2, offset);
            return getEndOfMonth(ctmp.getTime());
        }
    }

    public static Date getQuarterBegin(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = new GregorianCalendar();
            cal.setTime(date);
            int month = cal.get(2);
            int offset = -(month % 3);
            cal.add(2, offset);
            return getFirstOfMonth(cal.getTime());
        }
    }

    public static Date getQuarterEnd(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = new GregorianCalendar();
            cal.setTime(date);
            int month = cal.get(2);
            int offset = 2 - month % 3;
            cal.add(2, offset);
            return getEndOfMonth(cal.getTime());
        }
    }

    public static Date getYearBegin(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = GregorianCalendar.getInstance();
            cal.setTime(date);
            cal.set(2, 0);
            cal.set(5, 1);
            return cal.getTime();
        }
    }

    public static Date getYearEnd(Date date) {
        if (date == null) {
            return null;
        } else {
            Calendar cal = GregorianCalendar.getInstance();
            cal.setTime(date);
            cal.set(2, 11);
            return getEndOfMonth(cal.getTime());
        }
    }

    public static Date getDate(int year, int month, int day) {
        GregorianCalendar d = new GregorianCalendar(year, month - 1, day);
        return d.getTime();
    }

    public static List<Long> getDistanceTime(Date d1, Date d2, boolean includeDay) {
        long t1 = d1.getTime();
        long t2 = d2.getTime();
        long diff = Math.abs(t1 - t2);
        long day = diff / 86400000L;
        long hour = diff / 3600000L - day * 24L;
        long min = diff / 60000L - day * 24L * 60L - hour * 60L;
        long sec = diff / 1000L - day * 24L * 60L * 60L - hour * 60L * 60L - min * 60L;
        List<Long> times = new ArrayList(4);
        if (includeDay) {
            times.add(day);
            times.add(hour);
            times.add(min);
            times.add(sec);
            return times;
        } else {
            hour += day * 24L;
            times.add(hour);
            times.add(min);
            times.add(sec);
            return times;
        }
    }

    public static Date addYears(Date date, int years) {
        if (years == 0) {
            return date;
        } else if (date == null) {
            return null;
        } else {
            Calendar cal = GregorianCalendar.getInstance();
            cal.setTime(date);
            cal.add(1, years);
            return cal.getTime();
        }
    }

    public static String getCurrentTimeNo() {
        Date date = new Date();
        return formatDate(date, "yyyyMMddHHmmssSSS");
    }


}
